/**
* Copyright 2009 Waag Society <http://www.waag.org>
* This file is part of Annotrax.
*
* Annotrax is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Annotrax is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Annotrax.
* If not, see http://www.gnu.org/licenses/gpl.html
*/

/**
We get a list of annotations each containing a movie object refering to a fragment of the movie we get with a timed uri, consider it a playlist. Make a new video layer for each playlist item as soon as it starts playing, due to external control (user clicks), or due to internal control (next item)
*/
self.VideoPlayer = function(container,playlist)
{
	this.playlist = playlist;
	this.el_main = Element("div",{className:"video_player"},container)
	this.el_video_screen = Element("div",{className:"video_screen"},this.el_main)
	this.busy = new Busy(this.el_main)
	
	this.video_layers = new Array();
	this.current_playlist_item = null;
	this.current_el_video_layer = null;
	this.play();
	this.last_time_update = null;
	
	$(document).bind("annotation_click",bind(this,"onAnnotationEdit"));
	$(document).bind("play_button_click",bind(this,"play"));
	$(document).bind("pause_button_click",bind(this,"pause"));
	//$(document).bind("annotation_preview_click",bind(this,"onAnnotationEdit"));
	$(document).bind("progress_bar_click",bind(this,"onProgressBarClick"));
}
/**

*/
VideoPlayer.prototype.play = function()
{
	if(this.current_playlist_item)
	{
		this.current_playlist_item.el_video.play()
	}
	else
	{
		this.playItem(this.playlist[0],0);
	}
}
/**

*/
VideoPlayer.prototype.pause = function()
{
	if(this.current_playlist_item)
	{
		this.current_playlist_item.el_video.pause()
	}
}
/**
play the item, make a video layer for this item if it doesnt have one at the moment
*/
VideoPlayer.prototype.playItem = function(playlist_item, start_time, end_time)
{	
	this.busy.show()
	
	//hide and pause all other layers that are loaded
	this.current_playlist_item = playlist_item;

	for(var i=0;i<this.playlist.length;i++)
	{
		item = this.playlist[i];
		if(item.el_video != null)
		{
			item.el_video.pause();
			item.el_video.style.display = "none";
		}
	}

	//adds new video element if still needed, reloads the url if the start time has changed
	this.preLoadLayer(this.current_playlist_item,start_time,end_time);
	this.current_playlist_item.el_video.style.display = ""; //makes the element visible
	this.current_playlist_item.el_video.play();
	
	//always play from the beginning of video, we don't use currentTime to skim a video but ask the server for a trimmed piece
	try
	{
		this.current_playlist_item.el_video.currentTime = 0; 
	}
	catch(exception)
	{
		
	}
}
/**
get item following playlist_item, if there is one.
*/
VideoPlayer.prototype.getNextItem = function(playlist_item)
{
	for(var i=0;i<(this.playlist.length)-1;i++)
	{
		if(playlist_item == this.playlist[i])
		{
			return this.playlist[i+1];
		}
	}	
	return null;
}
/**
for each playlist item we make a seperate video layer so we can switch between items quickly without reloading in playlist mode
*/
VideoPlayer.prototype.preLoadLayer = function(playlist_item,start_time,end_time)
{
	//extra offset in case we search within a fragment or whole movie
	//the fragment we get from the server is chopped at the start time and may be shorter then the playlist item
	if(start_time == null)
	{
		start_time = 0; 
	}
	
	playlist_item.time_offset = Math.floor(start_time);
	
	//end time in case we were requested to play a preview for example, player stops at end time
	if(end_time != null)
	{
		playlist_item.end_preview = end_time;
	}
	
	//make the url for the chopped movie part
	s = playlist_item.getBeginTime() + start_time; //possible offset for this movie fragment because of user (search in fragment) interaction
	e = playlist_item.getEndTime();
	url = playlist_item.movie.getSrcUrl() + "?t=" + AnnotraxTime.startEndToTimeString(s,e);
			
	//create the video element for this playlist item if it is not yet there, 
	//reset the url and reload if the url has changed for this item (due to search within fragment)
	if(playlist_item.el_video == null)
	{	
		//create element
		el_video_layer = Element("video",{src:url,className:"video_layer",autoplay:false,control:true},this.el_video_screen)
		playlist_item.el_video = el_video_layer; 
		el_video_layer.playlist_item = playlist_item;
		el_video_layer.style.display = "none"; //default hide preload, we show in play
		
		//add listener to the video element
		el_video_layer.addEventListener("progress", bind(this,"onProgress",[playlist_item]),true );
		el_video_layer.addEventListener("play", bind(this,"onPlay",[playlist_item]),true );
		el_video_layer.addEventListener("pause", bind(this,"onPause",[playlist_item]),true );
		el_video_layer.addEventListener("timeupdate", bind(this,"onTimeUpdate",[playlist_item]),true );
		el_video_layer.addEventListener("ended", bind(this,"onEnded",[playlist_item]),true );
		
		//add to array of layers
		this.video_layers.push(el_video_layer);
		el_video_layer.load(); //load far enough to make a start fast	
	}
	else if(playlist_item.el_video.src != url) //reload with other url (time offset) on existing layer
	{
		playlist_item.el_video.src = url;
		playlist_item.el_video.load();
	}
}
VideoPlayer.prototype.test = function(cnt)
{
	console.log(cnt)
}


/**
show a particular playlist item (annotation)
*/
VideoPlayer.prototype.onAnnotationEdit = function(evt,channel,annotation)
{
	this.jumpTo(annotation)
}
/**
show a particular playlist item (annotation)
*/
VideoPlayer.prototype.onProgressBarClick = function(evt,item,offset)
{
	this.jumpTo(item,offset)
}
/**
jump to a particular playlist item with possible offset
*/
VideoPlayer.prototype.jumpTo = function(annotation,start,end)
{
	
	if(this.playlist.getIndex(annotation) != null)
	{
	
		this.playItem(annotation,start,end)
		return;
	}
	else //we are showing a single movie without annotation id, find the playlist item with same movie
	{
		playlist_item = this.playlist.findObj("movieId",annotation.movieId)
		if(playlist_item)
		{
			this.playItem(playlist_item,annotation.time,annotation.time+annotation.duration)
			return
		}
	}
	throw "you're asking the player to jump to an item that is not in the playlist"
}
/**
All playlist items report their progress while playing. Calculate the time of the play head in the original movie regarding the search offset with which the fragment was requested. Send event to possible other GUI elements
*/
VideoPlayer.prototype.onTimeUpdate = function(playlist_item,evt)
{	
	video_el = playlist_item.el_video //evt.originalTarget;	//get event elemen
	
	//check if we want to start a chain of updates, do not update within the same second 
	time_in_chop = Math.floor(video_el.currentTime)
	if(this.last_time_update == time_in_chop) 
	{
		return; 
	}
	this.last_time_update = time_in_chop
	
			
	if(playlist_item != this.current_playlist_item) //in case the older one is still playing??
	{ 
		video_el.pause();
	}
	else //the current one playing!
	{
		time_in_fragment = time_in_chop + playlist_item.time_offset //playhead position of currently playing item relative to the length of the ogg (possibly chopped)
		time_in_orginal_movie = time_in_fragment + playlist_item.getBeginTime() //playhead position of currently playing item relative to the original (unchopped) movie 
			
		//post event, other gui elements might want to update 
		$(document).trigger(jQuery.Event("player_progress"),[playlist_item,time_in_orginal_movie,time_in_fragment]); 
		
		//if there is a preview end time for this fragment
		if(playlist_item.end_preview != null)  
		{
			if(time_in_fragment >= playlist_item.end_preview) 
			{
				playlist_item.end_preview = null;
				playlist_item.el_video.pause();
			}
		}
		
		//in case it didn't receive an onended event		
		if(time_in_fragment >= playlist_item.duration) 
		{
			this.onEnded(playlist_item,evt);
		}
		
	}
}
/**
All playlist items report their loading progress while playing
*/
VideoPlayer.prototype.onProgress = function(playlist_item,evt)
{
	/*if(playlist_item == this.current_playlist_item) //extra zetje soms nodig
	{
		if(playlist_item.el_video.readyState > 2)
		{
			playlist_item.el_video.play();
		}
	}*/
}	
/**
As soon as the current item plays, we show the meta data and preload the next item 
*/
VideoPlayer.prototype.onPause = function(playlist_item,evt)
{	
	$(document).trigger(jQuery.Event("player_item_pause"),[playlist_item]); 
}
/**
As soon as the current item plays, we show the meta data and preload the next item 
*/
VideoPlayer.prototype.onPlay = function(playlist_item,evt)
{	
	//load the next item as soon as we are OK
	if(playlist_item == this.current_playlist_item)
	{		
		this.busy.hide()
		
		$(document).trigger(jQuery.Event("player_item_start"),[playlist_item]); 
		next_item = this.getNextItem(this.current_playlist_item);
		if(next_item != null)
		{
			this.preLoadLayer(next_item);
		}
	}
}
/**
Decide what should happen when the current pl item has ended 
*/
VideoPlayer.prototype.onEnded = function(playlist_item,evt)
{
	video_obj = playlist_item.el_video;//evt.originalTarget;

	if(video_obj.currentTime < video_obj.lastSetJumpTime ) 	//video has ended before the time set
	{
		alert("could not step to movie point (not yet loaded)")
	}
	
	next = this.getNextItem(playlist_item);
	if(next != null)
	{
		this.playItem(next);
	}
}

self.Busy = function(container)
{
	this.el_main = Element("div",{className:"busy"},container)
}
Busy.prototype.show = function()
{
	d = new Date()
	this.show_time = d.getTime()
	$(this.el_main).show()
}
Busy.prototype.hide = function()
{
	d = new Date()
	dif = d.getTime() -this.show_time
	if(dif < 1000)
	{
		setTimeout(bind(this,"reallyHide"),1000 - dif)
	}
	else
	{
		this.reallyHide()
	}	
}
Busy.prototype.reallyHide = function()
{
	$(this.el_main).hide()
}

